package ru.niir.goodfil.ui;

import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import ru.niir.goodfil.db.Client;
import ru.niir.goodfil.db.Role;
import ru.niir.goodfil.db.User;
import ru.niir.goodfil.db.dic.DeliveryType;
import ru.niir.goodfil.db.handlers.Goodfil;
import ru.niir.goodfil.ui.models.DetailedAbsenceByClientModel;
import ru.niir.goodfil.utils.DateFormat;
import ru.niir.goodfil.ui.utils.FilePublisher;
import ru.niir.goodfil.ui.utils.excel.unload.GoodAbsenceUnloading;

import javax.faces.model.SelectItem;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Бин для построения отчетов.
 */
public class ReportsBean extends PageBean
{

    private static final String TEMPLATE_PATH = ".clients.excel.template";
    private static final String TEMPLATE_PATH_DEFAULT = "C:\\clients_template.xls";

    private final Map<String, Integer> config = new HashMap<String, Integer>();
    private List<SelectItem> managers;

    private Date beginDate;
    private Date endDate;
    private long clientId;
    private int reportType;
    public ReportsBean()
    {
        config.put("Наименование компании", 0);
        config.put("Юридическое наименование компании", 1);
        config.put("Вид деятельности", 2);
        config.put("Специализация", 3);
        config.put("Сайт", 4);

        config.put("Клиент активен", 5);
        config.put("Контроль суммы закупок", 6);
        config.put("Заказы без согласования", 7);
        config.put("Номер в 1С", 8);

        config.put("Клиентская группа", 9);
        config.put("Менеджер", 10);

        config.put("Адрес фактический", 11);
        config.put("Адрес юридический", 12);
        config.put("Адрес доставки", 13);

        config.put("ФИО менеджера", 14);
        config.put("Рабочий телефон менеджера", 15);
        config.put("Мобильный телефон менеджера", 16);
        config.put("Email менеджера", 17);

        config.put("ФИО руководителя", 18);
        config.put("Рабочий телефон руководителя", 19);
        config.put("Мобильный телефон руководителя", 20);
        config.put("Email руководителя", 21);

        config.put("ФИО бухгалтера", 22);
        config.put("Рабочий телефон бухгалтера", 23);
        config.put("Мобильный телефон бухгалтера", 24);
        config.put("Email бухгалтера", 25);

        config.put("Комментарий", 26);
        config.put("Дата создания", 27);

        config.put("Величина ТК", 28);
        config.put("Оговоренная сумма закупок", 29);
        config.put("Долг по банку", 30);
        config.put("Долг по кассе", 31);
        config.put("Тип доставки", 32);
    }

    public List<SelectItem> getClientFields()
    {
        List<String> strs = new ArrayList<String>();
        for (String key : config.keySet()) strs.add(key);
        Collections.sort(strs);

        List<SelectItem> result = new ArrayList<SelectItem>();
        for (String str : strs) result.add(new SelectItem(str));
        return result;
    }

    public List<SelectItem> getManagers()
    {
        if (managers == null)
        {
            managers = new ArrayList<SelectItem>();
            List<User> users = gf().getManagers();
            for (User user : users) managers.add(new SelectItem(user.getId(), user.getFio()));
        }
        return managers;
    }

    private List selectedClientFields = new ArrayList();
    public List getSelectedClientFields()
    {
        return selectedClientFields;
    }

    public void setSelectedClientFields(List selectedClientFields)
    {
        this.selectedClientFields = selectedClientFields;
    }

    private List selectedManagers = new ArrayList();
    public void setSelectedManagers(List selectedManagers)
    {
        this.selectedManagers = selectedManagers;
    }

    public List getSelectedManagers()
    {
        return selectedManagers;
    }

    public static void generateClientsReport(Goodfil gf, Map<String, Integer> config, String[] fields, Long[] managers, String templatePath, String link) throws IOException
    {
        final Logger logger = Logger.getLogger(ReportsBean.class);

        //  Открываем шаблон
        logger.debug("Opening template");
        Workbook wb = new HSSFWorkbook(new FileInputStream(templatePath));
        Sheet sheet1 = wb.getSheetAt(0);
        logger.debug("  opened");

        //  Получаем всех клиентов и выбираем из них нужных
        logger.debug("Loading clients");
        List<Client> clients = gf.getClients();
        if (managers.length > 0)
        {
            List<Client> someClients = new ArrayList<Client>();
            for (Client client : clients)
                for (long manager : managers)
                    if (client.getManagerId() != null && client.getManagerId() == manager)
                        someClients.add(client);
            clients = someClients;
        }
        logger.debug("  loaded: " + clients.size());

        //  Устанавливаем клиентские группы
//        logger.debug("Loading client groups");
//        List<ClientGroup> clientGroups = gf.getClientGroups();
//        for (Client client : clients)
//            for (ClientGroup clientGroup : clientGroups)
//                if (clientGroup.getId() == client.getClientGroupId())
//                    client.setClientGroup(clientGroup);
//        logger.debug("  done");

        //  Устанавливаем менеджеров
        logger.debug("Loading managers");
        List<User> managersUsers = gf.getUsersByRoleId(Role.MANAGER);
        for (Client client : clients)
            if (client.getManagerId() != null)
                for (User user : managersUsers)
                    if (client.getManagerId() == user.getId())
                        client.setManager(user);
        logger.debug("  done");

        //  Начинаем формировать отчет
        logger.debug("Generating report");
        for (int i = 0; i < clients.size(); i++)
        {
            Client client = clients.get(i);
            logger.debug("  * [" + client.getId() + "] " + client.getCompanyName());

            Row row = sheet1.createRow(i + 1);
            for (String columnName : config.keySet())
            {
                int columnNum = config.get(columnName);
                String value = "?";

                if (columnName.equals("Наименование компании"))
                    value = client.getCompanyName();
                if (columnName.equals("Юридическое наименование компании"))
                    value = client.getLowName();
                if (columnName.equals("Вид деятельности"))
                    value = client.getCompanyType();
                if (columnName.equals("Специализация"))
                    value = client.getSpeciality();
                if (columnName.equals("Сайт"))
                    value = client.getSite();

                if (columnName.equals("Клиент активен"))
                    value = client.isActive() ? "да" : "нет";
                if (columnName.equals("Контроль суммы закупок"))
                    value = client.isAllowControlSum() ? "да" : "нет";
                if (columnName.equals("Заказы без согласования"))
                    value = client.isAllowQuickOrder() ? "да" : "нет";
                if (columnName.equals("Номер в 1С"))
                    value = client.getC1ClientNum();

                if (columnName.equals("Клиентская группа"))
                    value = "???";
//                    if (client.getClientGroup() != null)
//                        value = client.getClientGroup().getName();
                if (columnName.equals("Менеджер"))
                    if (client.getManager() != null)
                        value = client.getManager().getFio();

                if (columnName.equals("Адрес фактический"))
                    value = client.getAddressFact();
                if (columnName.equals("Адрес юридический"))
                    value = client.getAddressLaw();
                if (columnName.equals("Адрес доставки"))
                    value = client.getAddressDlv();

                if (columnName.equals("ФИО менеджера"))
                    value = client.getContactFio();
                if (columnName.equals("Рабочий телефон менеджера"))
                    value = client.getContactPhoneWork();
                if (columnName.equals("Мобильный телефон менеджера"))
                    value = client.getContactPhoneMob();
                if (columnName.equals("Email менеджера"))
                    value = client.getContactEmail();

                if (columnName.equals("ФИО руководителя"))
                    value = client.getBossFio();
                if (columnName.equals("Рабочий телефон руководителя"))
                    value = client.getBuhPhoneWork();
                if (columnName.equals("Мобильный телефон руководителя"))
                    value = client.getBossPhoneMob();
                if (columnName.equals("Email руководителя"))
                    value = client.getBossEmail();

                if (columnName.equals("ФИО бухгалтера"))
                    value = client.getBuhFio();
                if (columnName.equals("Рабочий телефон бухгалтера"))
                    value = client.getBuhPhoneWork();
                if (columnName.equals("Мобильный телефон бухгалтера"))
                    value = client.getBuhPhoneMob();
                if (columnName.equals("Email бухгалтера"))
                    value = client.getBuhEmail();

                if (columnName.equals("Комментарий"))
                    value = client.getComment();
                if (columnName.equals("Дата создания"))
                    value = new SimpleDateFormat("dd.MM.yyyy HH:mm").format(client.getCreationDate());

                if (columnName.equals("Величина ТК"))
                    value = String.valueOf(client.getMaxPrice());
                if (columnName.equals("Оговоренная сумма закупок"))
                    value = String.valueOf(client.getMinSum());
                if (columnName.equals("Долг по банку"))
                    value = String.valueOf(client.getDebtBank());
                if (columnName.equals("Долг по кассе"))
                    value = String.valueOf(client.getDebtCash());
                if (columnName.equals("Тип доставки"))
                    value = client.getDeliveryTypeId() == DeliveryType.SELF_DELIVERY ? "Самовывоз" : "Доставка транспортом компании";

                Cell cell = row.createCell(columnNum);
                cell.setCellType(Cell.CELL_TYPE_STRING);
                cell.setCellValue(value);
            }
        }

        //  Теперь удаляем лишние колонки
        logger.debug("Removing unnessesary columns");
        for (String columnName : config.keySet())
        {
            int columnNum = config.get(columnName);

            boolean found = false;
            for (String field : fields)
                if (columnName.equals(field))
                    found = true;

            if (!found) logger.debug("  * [" + columnNum + "] " + columnName);
            if (!found)
                for (int i = 0; i <= clients.size(); i++)
                    sheet1.setColumnWidth(columnNum, 0);
        }

        //  Теперь пишем выходной файл
        logger.debug("Writing output file to " + link);
        FileOutputStream fos = new FileOutputStream(link);
        wb.write(fos);
        fos.flush();
        fos.close();
        logger.debug("  done");
    }

    /**
     * Запустить настраиваемый отчет по клиентам 
     */
    public void doCustomClientsReport()
    {
        final Logger logger = Logger.getLogger(ReportsBean.class);

        try
        {
            List<String> l1 = new ArrayList<String>();
            for (Object o : getSelectedClientFields())
            {
                if (o instanceof SelectItem) l1.add(((SelectItem)o).getValue().toString());
                if (o instanceof String) l1.add((String)o);
            }
            String[] fields = new String[l1.size()];
            l1.toArray(fields);
            logger.debug("Fields to output: ");
            for (String field : fields)
                logger.debug(" * " + field);

            List<Long> l2 = new ArrayList<Long>();
            for (Object o : getSelectedManagers())
            {
                if (o instanceof SelectItem) l2.add((Long)((SelectItem)o).getValue());
                if (o instanceof Long) l2.add((Long)o);
            }
            Long[] managers = new Long[l2.size()];
            l2.toArray(managers);
            logger.debug("Managers to output: ");
            for (Long manager : managers)
                logger.debug(" * " + manager);

            gf().createIfNotExists(RestsExportBean.TEMP_CATALOG, RestsExportBean.DEFAULT_TEMP_CATALOG, "Каталог временных файлов");
            String tempCatalog = gf().get(RestsExportBean.TEMP_CATALOG);
            logger.debug("Temp catalog is: " + tempCatalog);

            gf().createIfNotExists(TEMPLATE_PATH, TEMPLATE_PATH_DEFAULT, "Шаблон для отчета по клиентам");
            String templatePath = gf().get(TEMPLATE_PATH);
            logger.debug("Template catalog is: " + templatePath);

            String uid = UUID.randomUUID().toString();
            logger.debug("Report uid is: " + uid);

            String tempFile = tempCatalog + File.separator + uid + ".xls";
            logger.debug("Temp file is: " + tempFile);

            generateClientsReport(gf(), config, fields, managers, templatePath, tempFile);
            logger.debug("Generated successfuly!");

            logger.debug("Publishing...");
            String link = FilePublisher.retrieveFile(request(), tempFile, uid + ".xls");
            logger.debug("Published to: " + link);
            response().sendRedirect(link);
        }
        catch (IOException e)
        {
            logger.debug(e);
            facesError("Невозможно выполнить выгрузку данных");
        }
    }

    public void getClientAbsence(){
        List list;
        if(getReportType() == 1){
            list = gf().getAbsenceByClient(beginDate, endDate, clientId);
        }
        else {list = gf().getDeliveriesByClient(beginDate, endDate, clientId);}

        if(list.size() == 0) {
            facesError("Нет элементов для выгрузки");
            return;
        }
        List<DetailedAbsenceByClientModel> result = new ArrayList<DetailedAbsenceByClientModel>();
        for(Object o : list){
            Object[] arr = (Object[])o;
            long idGood = ((BigInteger)arr[0]).longValue();
            int goodCount = ((BigDecimal)arr[1]).intValue();
            int inquriesCount = ((BigInteger)arr[2]).intValue();
            double sum = (Double)arr[3];
            DetailedAbsenceByClientModel model = new DetailedAbsenceByClientModel();
            model.setGoodCode(gf().getGoodById(idGood).getCode());
            model.setGoodCount(goodCount);
            model.setInquriesCount(inquriesCount);
            model.setSum(sum);
            result.add(model);
        }
        StringBuilder companyName = new StringBuilder();
        companyName.append("Клиент: " + gf().getClientById(clientId).getCompanyName() + " .");

        StringBuilder sb = new StringBuilder();
        sb.append(getReportType() == 1 ? "Нехватка за период: " : "Отгружено за период: ");
        sb.append(DateFormat.FormatDate(beginDate) + " - " + DateFormat.FormatDate(endDate));
        GoodAbsenceUnloading.goodAbsenceUnloadingByClient(result, companyName.toString(), sb.toString());
    }

    public void getManagerAbsenceOrDeliveries(){
        List list;
        long managerId = getSecurityBean().getCurrentUser().getId();
        if(getReportType() == 1){
            list = gf().getAbsenceByManager(beginDate, endDate, managerId);
        }
        else {list = gf().getDeliveriesByManager(beginDate, endDate, managerId);}

        if(list.size() == 0) {
            facesError("Нет элементов для выгрузки");
            return;
        }
        List<DetailedAbsenceByClientModel> result = new ArrayList<DetailedAbsenceByClientModel>();
        for(Object o : list){
            Object[] arr = (Object[])o;
            long idGood = ((BigInteger)arr[0]).longValue();
            int goodCount = ((BigDecimal)arr[1]).intValue();
            int inquriesCount = ((BigInteger)arr[2]).intValue();
            double sum = (Double)arr[3];
            DetailedAbsenceByClientModel model = new DetailedAbsenceByClientModel();
            model.setGoodCode(gf().getGoodById(idGood).getCode());
            model.setGoodCount(goodCount);
            model.setInquriesCount(inquriesCount);
            model.setSum(sum);
            result.add(model);
        }
        StringBuilder companyName = new StringBuilder();
        companyName.append("Выгрузка по всем клиентам");

        StringBuilder sb = new StringBuilder();
        sb.append(getReportType() == 1 ? "Нехватка за период: " : "Отгружено за период: ");
        sb.append(DateFormat.FormatDate(beginDate) + " - " + DateFormat.FormatDate(endDate));
        GoodAbsenceUnloading.goodAbsenceUnloadingByClient(result, companyName.toString(), sb.toString());
    }

    public List<Goodfil.RestsError> getRestsOndOrdersItems()
    {
        return gf().getRestsErrors();        
    }

    private List<Client> clients;

    public List<SelectItem> getAllClientsAsSelectItems() {
        if (clients == null) clients = gf().getClients();

        List<SelectItem> result = new ArrayList<SelectItem>();
        for (Client client : clients) {
            if (client.getManagerId() != null && getSecurityBean().isManagerCorrect(client.getManagerId()))
                result.add(new SelectItem(client.getId(), client.getCompanyName()));
        }
        return result;
    }

    public Date getBeginDate() {
        return beginDate;
    }

    public void setBeginDate(Date beginDate) {
        this.beginDate = beginDate;
    }

    public Date getEndDate() {
        return endDate;
    }

    public void setEndDate(Date endDate) {
        this.endDate = endDate;
    }

    public long getClientId() {
        return clientId;
    }

    public void setClientId(long clientId) {
        this.clientId = clientId;
    }

    public int getReportType() {
        return reportType;
    }

    public void setReportType(int reportType) {
        this.reportType = reportType;
    }
}
